using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using CS6238Project2.Banking.Communication;
using CS6238Project2.Banking.Commerce;
using CS6238Project2.Banking.Tools;
using System.Net.Security;
using System.Security.Cryptography;

namespace CS6238Project2.Banking.Tools
{


    class CSocketPacket
    {

        public System.Net.Sockets.Socket thisSocket;
        public byte[] dataBuffer = new byte[100*1024];
    }
    class packet
    {
        public bool rsa;

        public byte[] data;
        public string senderPK;

    }
    class server
    {

        public delegate void ParcelDelegate(Parcel parcel);

        public event ParcelDelegate ParcelPassed;


        protected void OnParcelPassed(Parcel parcel)
        {
            if (ParcelPassed != null)
            {
                ParcelPassed(parcel);
            }
        }

        //private byte[] m_DataBuffer = new byte[4096];
        private Socket m_socListener;
        //private Socket m_socWorker;
        //private transmitter t;
        private IPEndPoint ipLocal;
        private int port;
        private RSACryptoServiceProvider RSA;
        private string publicK;
        private string privateK;
        // create the socket...
        public server(int port, string publicKey)
        {
            this.port = port;
            CspParameters parms = new CspParameters();

            //Needs to use the MachineKeyStore otherwise ASP.net application 
            //wont work
            parms.Flags = CspProviderFlags.UseMachineKeyStore;
            RSA = new RSACryptoServiceProvider(parms);
            publicK = RSA.ToXmlString(false);
            privateK = RSA.ToXmlString(true);

            {
                try
                {
                    //create the listening socket...
                    m_socListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    //int iPortNo = System.Convert.ToInt32(port, 10);

                    ipLocal = new IPEndPoint(IPAddress.Any, port);

                    //bind to local IP Address...
                    m_socListener.Bind(ipLocal);
                    //start listening...
                    m_socListener.Listen(128);
                    // create the call back for any client connections...
                    m_socListener.BeginAccept(new AsyncCallback(OnClientConnect), null);

                }
                catch (SocketException se)
                {
                    Console.WriteLine(se);
                }

            }
        }
        public void OnClientConnect(IAsyncResult asyn)
        {
            try
            {
                Socket m_socWorker = m_socListener.EndAccept(asyn);

                WaitForData(m_socWorker);
            }
            catch (ObjectDisposedException e)
            {
                Console.WriteLine(e);
            }
            catch (SocketException se)
            {
                Console.WriteLine(se);
            }

        }
        public void Send(string IPaddr, int po, Parcel data)
                 {
                     data.SenderPort = this.port;
                     packet p = new packet();
                     p.rsa = false;
                     p.data = Encryption.StringToUTF8ByteArray(Encryption.XmlString(data));
                     if (data.Type.Equals("Registration Response"))
                     {
                         p.rsa = true;
                         p.senderPK = this.publicK;
                         if(data.Type.Equals("Registration Request"){
                             string key = ;
                         }else{
                             string key = ;
                         }
                         encrypt(p,key);
                     }
                     
                     new socket(IPaddr, po, p);
                 }
        public void WaitForData(Socket m_socWorker)
        {
            CSocketPacket SP = new CSocketPacket();
            SP.thisSocket = m_socWorker;
            AsyncCallback pfnCallBack = new AsyncCallback(OnDataReceived);
            // now start to listen for any data...
            IAsyncResult m_asynResult =
            m_socWorker.BeginReceive(SP.dataBuffer, 0, SP.dataBuffer.Length, SocketFlags.None, pfnCallBack, SP);
        }
        public void encrypt(packet p, string key)
        {
            RSACryptoServiceProvider temp = Crypto.CreateRSA(key);
            p.data = temp.Encrypt(p.data, false);
        }
        public void decrypt(packet p)
        {
            p.data = RSA.Decrypt(p.data, false);
        }
        public void OnDataReceived(IAsyncResult asyn)
        {


            CSocketPacket PS = (CSocketPacket)asyn.AsyncState;
            PS.thisSocket.EndReceive(asyn);
            string temp = Encryption.UTF8ByteArrayToString(PS.dataBuffer);
            packet p = (packet)Encryption.Destring(temp, typeof(packet));
            if (p.rsa)
            {
                decrypt(p);
            }
            temp = Encryption.UTF8ByteArrayToString(p.data);
            Parcel parcel = (Parcel)Encryption.Destring(temp, typeof(Parcel));
            //t.process(p);
            OnParcelPassed(parcel);
            // create the call back for any client connections...
            m_socListener.Close();
            m_socListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            m_socListener.Bind(ipLocal);
            //start listening...
            m_socListener.Listen(128);
            m_socListener.BeginAccept(new AsyncCallback(OnClientConnect), null);



            //WaitForData();
        }
        public void close()
        {
            m_socListener.Close();
            //m_socWorker.Close();
        }
    }
}
